#include "mytest.h"

#include "TransferType.h"
#include "tcpblock.h"
#include "FileBlock.h"
#include "filemanager.h"

#include <QThread>
#include <QDebug>
#include <QDataStream>

#include <QElapsedTimer>

MyTest::MyTest(QObject *parent) :
    QObject(parent)
{
    using namespace std::placeholders;

    m_thread = new QThread;
    moveToThread(m_thread);
    m_thread->start();
    qDebug() << "MyTest run in" << thread();
    TcpManager* tcpManager = TcpManager::instance();
    connect(tcpManager, SIGNAL(newConnection(QSharedPointer<TransferSocket>)),
            this, SLOT(onNewConnection(QSharedPointer<TransferSocket>)),
            Qt::QueuedConnection);

    tcpManager->registerFunctor(FILE_HEADER, std::bind(&MyTest::onRecvNewFile, this, _1, _2));
    tcpManager->registerFunctor(FILE_BODY, std::bind(&MyTest::onNewFileBody, this, _1, _2));
}

MyTest::~MyTest()
{
    m_thread->exit();
    delete m_thread;
}


struct FileRecord {
    FileHeader header;
    QSharedPointer<QFile> file;
    qint64 recvSize;
};

static QHash<decltype(TcpBlock::magicNumber), FileRecord> fileHash;


QElapsedTimer timer;
void MyTest::onRecvNewFile(qint64 magic, QByteArray data)
{
    if (!runInLoop()) {
        QMetaObject::invokeMethod(this, "onRecvNewFile",
                                  Q_ARG(qint64, magic),
                                  Q_ARG(QByteArray, std::move(data)));
        return;
    }
    timer.start();
    FileRecord record;
    FileHeader header = FileHeader::fromByteArray(data);
    FileManager *fileManager = FileManager::instance();
    qDebug() << "Recv new file" << header.fileName << "magic" << magic;
    auto file = fileManager->openForWrite(fileManager->fileRecvPath() + "\\" + header.fileName);

    record.header   = header;
    record.file     = file;
    record.recvSize = 0;

    fileHash[magic] = record;
}

void MyTest::onNewFileBody(qint64 magic, QByteArray data)
{  
    if (!runInLoop()) {
        QMetaObject::invokeMethod(this, "onNewFileBody",
                                  Q_ARG(qint64, magic),
                                  Q_ARG(QByteArray, std::move(data)));
        return;
    }
    static qint64 offset = 0;
    FileRecord& record = fileHash[magic];
    auto file = record.file;
    qint64 size = data.size();
    record.recvSize += size;
    file->write(std::move(data));
    if (record.recvSize == record.header.fileSize) {
        qDebug() << "File" << record.header.fileName << "receivce completed.";
        file->close();
    }
    if (timer.elapsed() >= 1000 || record.recvSize == record.header.fileSize) {
        timer.restart();
        qDebug() << "Recv speed" << (record.recvSize - offset) / 1024 / 1024 << "MB/s";
        offset = record.recvSize;
    }
}


void MyTest::onNewConnection(QSharedPointer<TransferSocket> socket)
{
    FileManager *fileManager = FileManager::instance();
    auto file = fileManager->openForRead("xx\\CentOS-7-x86_64-DVD-2003.iso");

    socket->sendFile(file);
    connect(socket.get(), SIGNAL(sendFileComplete(QSharedPointer<QFile>)),
            this, SLOT(onSendFileComplete(QSharedPointer<QFile>)));
}

void MyTest::onSendFileComplete(QSharedPointer<QFile> file)
{
    file->close();
}

bool MyTest::runInLoop() const
{
    return QThread::currentThread() == thread();
}
